home *** CD-ROM | disk | FTP | other *** search
- ; Program Name: PRG_3CP.S
-
- ; Assembly Instructions:
-
- ; Assemble in PC-relative mode and save with a TOS extension.
-
- ; Execution Instructions:
-
- ; Execute from the desktop. Terminate execution by pressing the Return
- ; key.
-
- ; Function:
-
- ; This program is divided into two parts. Part 1 verifies that the
- ; results from two binary to ASCII decimal conversion algorithms are
- ; identical. The first conversion algorithm is called the "repeated
- ; division" method; the number to be converted is repeatedly divided by 10.
- ; The second algorithm is called the "repeated subtraction" method; powers
- ; of ten are repeatedly subtracted from the number to be converted.
-
- ; Part 2 compares the two algorithms to determine which is the faster.
-
- ; Part 1 contains three sections. Section 1 confirms that both algorithms
- ; yield the same result for a positive number; section 2 confirms identical
- ; results for a negative number; section 3 confirms identical results for
- ; the number zero.
-
- ; A FEW NOTES:
-
- ; 1 - "clr.w Dn" is one of the fastest ways to clear only the lower word
- ; of a data register.
-
- ; 2 - The stack used in the program is small enough to permit easy access
- ; to its contents via the AssemPro debugger.
-
- ; 3 - In the "repeated division" algorithm, a null character must be stored
- ; in the array "reversed" for proper operation of the
- ; "reversed_to_decimal" loop when the program is executed from AssemPro.
- ; This is true because AssemPro will not necessarily clear the array to
- ; zeroes.
-
- ; When the program is executed from the desktop, however, the operating
- ; system will clear the array. Therefore, if the program were intended
- ; for use such as it is, the instruction which stores the null at the
- ; end of the array "reversed" could be eliminated.
-
- ; This is only one of the many types of adjustments
- ; which must be made when executing programs from debuggers.
-
- calculate_program_size:
- lea program_end, a0 ; Put "end of program" address in A0.
- movea.l 4(a7), a1 ; Put "basepage" address in A1.
- suba.l a1, a0 ; Subtract basepage address from A0.
- lea stack, a7 ; Point A7 to this program's stack.
-
- return_memory: ; Return unused memory to operating system.
- pea (a0) ; Store total program length in stack.
- pea (a1) ; Store basepage address in stack.
- move.l #$4A0000, -(sp) ; Function = m_shrink = GEMDOS $4A.
-
- ; NOTE: The above instruction is a combination of two that are often seen
- ; in references:
-
- ; move.w d0, -(sp) ; Dummy value, can be anything.
- ; move.w #$4a, -(sp) ; Function = m_shrink = GEMDOS $4A.
-
- trap #1 ; GEMDOS call.
- lea $C(sp), sp ; Reset stack pointer to top of stack.
-
- mainline: ; Marks the beginning of program proper.
- lea heading, a0 ; Print heading for program's output.
- bsr print_string
-
- ;
- ; PART 1, SECTION 1: Conversion of a positive binary number to ASCII decimal.
- ;
-
- lea part_1_head, a0 ; Print PART 1 heading.
- bsr print_string
- lea sect_1_head, a0 ; Print SECTION 1 heading.
- bsr print_string
-
- repeated_division_1:
- lea division_head, a0 ; Print heading for division results.
- bsr print_string
- move.l #2147483647, d1 ; Number to be converted must be in D1.
- bsr bin_to_dec_1 ; ASCII decimal string stored in "decimal".
- lea decimal, a0 ; Print ASCII decimal string.
- bsr print_string
-
- ; NOTE: Remember, although the number we store in D1 appears to our eyes
- ; to be a very familiar decimal number, the computer does not see
- ; it that way. It is the assembler that lets us see things that
- ; are palatable to us while we are programming, and which, during
- ; assembly, converts that which we like to something the computer
- ; likes. And the computer likes binary.
-
- repeated_subtraction_1:
- lea subtract_head, a0 ; Print heading for subtraction results.
- bsr print_string
- move.l #2147483647, d1 ; Number to be converted must be in D1.
- bsr bin_to_dec_2 ; ASCII decimal string stored in "decimal".
- lea decimal, a0 ; Print ASCII decimal string.
- bsr print_string
- bsr print_newlines
-
- ;
- ; PART 1, SECTION 2: Conversion of a negative binary number to ASCII decimal.
- ;
-
- lea sect_2_head, a0 ; Print SECTION 2 heading.
- bsr print_string
-
- repeated_division_2:
- lea division_head, a0 ; Print heading for division results.
- bsr print_string
- move.l #-7483647, d1
- bsr bin_to_dec_1
- lea decimal, a0
- bsr print_string
-
- repeated_subtraction_2:
- lea subtract_head, a0 ; Print heading for subtraction results.
- bsr print_string
- move.l #-7483647, d1
- bsr bin_to_dec_2
- lea decimal, a0
- bsr print_string
- bsr print_newlines
-
- ;
- ; PART 1, SECTION 3: Conversion of binary number zero to ASCII decimal.
- ;
-
- lea sect_3_head, a0 ; Print SECTION 3 heading.
- bsr print_string
-
- repeated_division_3:
- lea division_head, a0 ; Print heading for division results.
- bsr print_string
- move.l #0, d1
- bsr bin_to_dec_1
- lea decimal, a0
- bsr print_string
-
- repeated_subtraction_3:
- lea subtract_head, a0 ; Print heading for subtraction results.
- bsr print_string
- move.l #0, d1
- bsr bin_to_dec_2
- lea decimal, a0
- bsr print_string
- bsr print_newlines
-
- ;
- ; PART 2: Repeated division algorithm versus repeated subtraction algorithm
- ; execution speed comparision. Each algorithm is executed 1000 times.
- ;
-
- lea part_2_head, a0 ; Print PART 2 heading.
- bsr print_string
-
- repeated_division_method:
- lea div_time_head, a0
- bsr print_string
- move.l #9999, d7 ; D7 is counter for the push loop.
- bsr get_time ; Value of system clock returned in D5.
- move.l d5, d6 ; Save time in scratch register.
- division_loop:
- move.l #1928374650, d1 ; Number to be converted to ASCII decimal.
- bsr bin_to_dec_1
- dbra d7, division_loop ; Loop 1000 times.
- bsr get_time ; Get current value of system clock.
- sub.l d6, d5 ; Subtract beginning value from ending value.
- mulu #5, d5 ; Convert to milliseconds.
- move.l d5, d1 ; Transfer value for conversion to ASCII decimal.
- bsr bin_to_dec_2 ; Convert.
- lea decimal, a0 ; Print repeated division algorithm time.
- bsr.s print_string
- lea units_label, a0 ; Print time label.
- bsr.s print_string
-
- repeated_subtraction_method:
- lea sub_time_head, a0
- bsr.s print_string
- move.l #9999, d7 ; D7 is counter for the push loop.
- bsr get_time ; Value of system clock returned in D5.
- move.l d5, d6 ; Save time in scratch register.
- subtraction_loop:
- move.l #1928374650, d1 ; Number to be converted to ASCII decimal.
- bsr bin_to_dec_2
- dbra d7, subtraction_loop; Loop 1000 times.
- bsr get_time ; Get current value of system clock.
- sub.l d6, d5 ; Subtract beginning value from ending value.
- mulu #5, d5 ; Convert to milliseconds.
- move.l d5, d1 ; Transfer value for conversion to ASCII decimal.
- bsr bin_to_dec_2 ; Convert.
- lea decimal, a0 ; Print repeated division algorithm time.
- bsr.s print_string
- lea units_label, a0 ; Print time label.
- bsr.s print_string
-
- wait_for_keypress:
- move.w #8, -(sp) ; Function = c_necin = GEMDOS $8.
- trap #1 ; GEMDOS call.
- addq.l #2, sp ; Reposition stack pointer at top of stack.
-
- terminate:
- move.w #0, -(sp) ; Function = p_term_old = GEMDOS $0.
- trap #1 ; GEMDOS call.
-
- ;
- ; SUBROUTINES
- ;
-
- print_string: ; Expects address of string to be in A0.
- move.l a0, -(sp) ; Push address of string onto stack.
- move.w #9, -(sp) ; Function = c_conws = GEMDOS $9.
- trap #1 ; GEMDOS call
- addq.l #6, sp ; Reposition stack pointer.
- rts
-
- print_newlines: ; Prints 2 carriage returns and linefeeds.
- pea newlines ; Push address of string onto stack.
- move.w #9, -(sp) ; Function = c_conws = GEMDOS $9.
- trap #1 ; GEMDOS call
- addq.l #6, sp
- rts
-
- ; Get_time subroutine. Returns current value of system clock in D5.
-
- ; The get_time subroutine obtains the current value of the system variable
- ; _hz_200 (memory location $4BA). This variable is incremented every 200
- ; hertz, which means that the period between increments is 5 milliseconds
- ; (1/200 = .005). In turn, this means that the variable measures time with
- ; a resolution of 5 milliseconds.
-
- ; Use this subroutine to measure the elapsed time of an event as follows:
-
- ; 1. Read and store the content of $4BA at the beginning of the event.
- ; 2. At the conclusion of the event, read the content of $4BA again.
- ; 3. Subtract the first value from the second. This yields the number of
- ; 5 millisecond intervals which occurred during the event.
- ; 4. Multiply the difference by 5 to convert the elapsed time to milliseconds.
-
- get_time: ; Get number of 5 msec periods.
- move.l #0, -(sp) ; The zero turns on supervisor mode.
- move.w #$20, -(sp) ; Function = super = GEMDOS $20.
- trap #1 ; Go to supervisor mode.
- addq.l #6, sp ; Supervisor stack pointer returned in D0.
- move.l $4BA, d5 ; Copy system time into register D5
- move.l d0, -(sp) ; Restore supervisor stack pointer.
- move.w #$20, -(sp) ; Function = super = GEMDOS $20.
- trap #1 ; Go to user mode.
- addq.l #6, sp ; Reset stack pointer to top of stack.
- rts
-
- ; The binary to ASCII decimal conversion subroutine uses an algorithm
- ; based on the "repeated division" algorithm discussed in chapter 9 of the
- ; Ford & Topp book; however, the algorithm used here is not limited to a
- ; 16-bit binary number. There is a similar algorithm in the Atari section
- ; of appendix B in the Skinner book. The divisor is decimal 10.
-
- bin_to_dec_1: ; Converts 32-bit binary number in D1 to
- ; ASCII decimal.
- lea decimal, a0 ; Point to beginning of array "decimal".
- lea reversed + 10, a1 ; Point to end of array "reversed".
- move.b #0, (a1) ; Put a null at the end of the array.
- _get_sign:
- tst.l d1 ; Is binary number positive, negative or zero?
- beq.s _zero_passed ; Branch if number is 0.
- bpl.s _positive ; Branch if positive.
- move.b #$2D, (a0)+ ; Store a minus sign in array decimal.
- neg.l d1 ; Change number from negative to positive.
- bra.s _division_loop
- _positive: ; Branch to here when number is positive.
- move.b #$20, (a0)+ ; Store a space in array decimal.
- _division_loop:
- move.w d1, d2 ; Store lower word in temp register D2.
- clr.w d1 ; Clear lower word.
- swap d1 ; Move higher word to lower word.
- divu #10, d1 ; Divide full 32 bits by ten.
- move.w d1, d3 ; Store quotient in temp register D3.
- move.w d2, d1 ; Combine lower word with remainder.
- divu #10, d1 ; Divide full 32 bits by ten.
- swap d1 ; Swap quotient and remainder words.
- _convert_to_ascii: ; Convert digit to ASCII and store it.
- addi.b #$30, d1 ; Convert digit to ASCII.
- move.b d1, -(a1) ; Store the digit in array "reversed".
- move.w d3, d1 ; Bring in higher word quotient.
- swap d1 ; Swap high and low word quotients.
- tst.l d1 ; Is content of D1 zero yet?
- bne.s _division_loop ; Continue until content of D1 is zero.
- reversed_to_decimal: ; Transfer contents of "reversed" to "decimal".
- move.b (a1)+, (a0)+ ; Loop until the null is transfered.
- bne.s reversed_to_decimal
- rts
- _zero_passed:
- move.b #$20, (a0)+ ; Store a space in array "decimal".
- move.b #$30, (a0)+ ; Store the zero in array "decimal".
- move.b #0, (a0) ; Terminate the decimal string with a null.
- rts
-
- ; Conversion from binary to ASCII decimal using repeated subtraction.
- ; See documentation in program PRG_3AP.S.
-
- bin_to_dec_2:
- lea decimal, a0 ; Put address of array "decimal" in A0.
- lea subtrahend, a1 ; Put address of subtrahend table in A1.
- move.l (a1)+, d0 ; Put first subtrahend in D0.
- move.b #$30, d2 ; Initialize subtractions counter to ASCII zero.
- get_sign:
- tst.l d1 ; Is binary number positive, negative or zero?
- beq.s zero_passed ; Branch if number is 0.
- bpl.s positive ; Branch if positive.
- move.b #$2D, (a0)+ ; Store a minus sign in array "decimal".
- neg.l d1 ; Change binary number from neg to pos.
- bra.s discard_leading_zeroes
- positive: ; Branch to here when number is positive.
- move.b #$20, (a0)+ ; Store a space in array decimal.
- discard_leading_zeroes: ; Subtract subtrahend from minuend.
- sub.l d0, d1 ; Loop till difference is positive,
- bpl.s subtract ; indicating that digit is not zero.
- add.l d0, d1 ; Restore minuend.
- move.l (a1)+, d0 ; Get next subtrahend.
- bra.s discard_leading_zeroes
- subtract:
- addq.b #1, d2 ; Increment subtractions counter.
- sub.l d0, d1 ; Subtract subtrahend from D1.
- bpl.s subtract ; Loop until D1 becomes negative.
- move.b d2, (a0)+ ; Store the ASCII digit in array "decimal".
- loop_setup:
- add.l d0, d1 ; Restore the minuend.
- move.b #$2F, d2 ; Pre-initialize subtractions counter to $30-1.
- move.l (a1)+, d0 ; Get next subtrahend.
- bne.s subtract ; Loop back until subtrahend = 0.
- move.b #0, (a0) ; Terminate decimal string with a null.
- rts
- zero_passed:
- move.b #$20, (a0)+ ; Store a space in array "decimal".
- move.b d2, (a0)+ ; Store an ASCII zero in array "decimal".
- move.b #0, (a0) ; Terminate ASCII decimal string with a null.
- rts
-
- data
- subtrahend: dc.l $3B9ACA00,$5F5E100,$989680,$F4240,$186A0,$2710,$3E8
- dc.l $64,$A,$1,$0
- heading: dc.b 'PRG_3CP Execution Results',$D,$A,$D,$A,0
- part_1_head: dc.b ' Part 1: Conversion Verification',$D,$A,$D,$A,0
- sect_1_head: dc.b ' Section 1: Positive Number Conversion',$D,$A,$D,$A,0
- sect_2_head: dc.b ' Section 2: Negative Number Conversion',$D,$A,$D,$A,0
- sect_3_head: dc.b ' Section 3: Converson for Zero',$D,$A,$D,$A,0
- division_head: dc.b ' Decimal value by repeated division method: ',0
- subtract_head: dc.b $D,$A
- dc.b ' Decimal value by repeated subtraction method: ',0
- part_2_head: dc.b ' Part 2: Execution Speed Results',$D,$A,$D,$A,0
- time_head: dc.b ' Times for 1000 executions of each conversion method.',0
- div_time_head: dc.b ' Elapsed time for repeated division method: ',0
- sub_time_head: dc.b ' Elapsed time for repeated subtraction method: ',0
- units_label: dc.b ' milliseconds',$D,$A,0
- newlines: dc.b $D,$A,$D,$A,0
- bss
- align ; Align storage on a word boundary.
- reversed: ds.l 3 ; Temp buffer for the repeated division method.
- decimal: ds.l 3 ; Output buffer, must be NULL terminated.
- ds.l 24 ; Program stack, short enough for examination.
- stack: ds.l 0 ; Address of program stack.
- program_end: ds.l 0 ; Marks the end of program memory.
- end